advanced operations on grids
!! advanced operations on grids !|author: <a href="mailto:giovanni.ravazzani@polimi.it">Giovanni Ravazzani</a> ! license: <a href="http://www.gnu.org/licenses/">GPL</a> ! !### History ! ! current version 1.8 - 19th January 2021 ! ! ! | Version | Date | Comment | ! |---------|-------------|------------------| ! | 0.1 | 29/Jun/2009 | Original code. giovanni ravazzani | ! | 0.2 | 09/Aug/2009 | Added GridByIni | ! | 0.3 | 07/Apr/2010 | Added GridResample | ! | 0.4 | 16/Oct/2010 | function to compute cell area and distance | ! | 0.5 | 03/Feb/2011 | Distance moved to GeoLib | ! | 0.6 | 01/Aug/2011 | optional argument for cellsize output from GridConvert | ! | 0.7 | 19/Oct/2011 | added getSum routines | ! | 0.8 | 03/Dec/2012 | GetMin function | ! | 0.9 | 20/Mar/2013 | correct a bug in SUBROUTINE ResampleFloat | ! | 1.0 | 09/Apr/2013 | MinMaxNormalization and GetMax routines | ! | 1.1 | 11/Apr/2013 | ZscoreNormalization and GetStDev routines | ! | 1.2 | 12/Mar/2016 | GetRMSE function to compute Root Mean Square Error between two grids real | ! | 1.3 | 10/May/2016 | GetBias function to compute Bias between two grids real | ! | 1.4 | 19/Dec/2016 | statistic routines moved to new module GridStatistics | ! | 1.5 | 28/Nov/2017 | GridByIni modified to read epsg code | ! | 1.6 | 03/Mar/2018 | Added functions CellIsNoData and CellIsValid | ! | 1.7 | 28/Jan/2020 | Grid2vector subroutine to transform grid content to an array 1D | ! | 1.8 | 19/Jan/2021 | Added CellLength, moved ExtractBorder from function to subroutine | ! !### License ! license: GNU GPL <http://www.gnu.org/licenses/> ! ! This file is part of ! ! MOSAICO -- MOdular library for raSter bAsed hydrologIcal appliCatiOn. ! ! Copyright (C) 2011 Giovanni Ravazzani ! !### Module Description: ! library to operate on grids MODULE GridOperations ! History: ! Modules used: USE DataTypeSizes, ONLY: & ! Imported type definitions: short, long, float USE LogLib, ONLY: & ! Imported routines: Catch USE ErrorCodes, ONLY: & !Imported parameters: memAllocError, unknownOption USE GridLib, ONLY: & !Imported type definitions: grid_integer, grid_real, & ! Imported routines: NewGrid, SyncTime, & !Imported parameters: ESRI_ASCII, ESRI_BINARY, NET_CDF USE GeoLib, ONLY: & !Imported operators: OPERATOR (==) IMPLICIT NONE !global (public declarations) INTERFACE ASSIGNMENT(=) MODULE PROCEDURE AssignGridReal MODULE PROCEDURE AssignGridInteger MODULE PROCEDURE AssignReal MODULE PROCEDURE AssignInteger MODULE PROCEDURE AssignGridRealInteger MODULE PROCEDURE AssignGridIntegerReal END INTERFACE INTERFACE GridConvert MODULE PROCEDURE GridConvertFloat MODULE PROCEDURE GridConvertInteger END INTERFACE INTERFACE GridShift MODULE PROCEDURE ShiftInteger MODULE PROCEDURE ShiftReal END INTERFACE INTERFACE GetXY MODULE PROCEDURE GetXYFloat MODULE PROCEDURE GetXYInteger END INTERFACE INTERFACE GetIJ MODULE PROCEDURE GetIJFloat MODULE PROCEDURE GetIJInteger END INTERFACE INTERFACE CRSisEqual MODULE PROCEDURE CRSisEqualIntInt MODULE PROCEDURE CRSisEqualFloatFloat MODULE PROCEDURE CRSisEqualFloatInt MODULE PROCEDURE CRSisEqualIntFloat END INTERFACE INTERFACE GridByIni MODULE PROCEDURE GridByIniFloat MODULE PROCEDURE GridByIniInteger MODULE PROCEDURE GridByIniFloatSubSection MODULE PROCEDURE GridByIniIntegerSubSection END INTERFACE INTERFACE IsOutOfGrid MODULE PROCEDURE IsOutOfGridFloat MODULE PROCEDURE IsOutOfGridInteger END INTERFACE INTERFACE ExtractBorder MODULE PROCEDURE ExtractBorderFloat MODULE PROCEDURE ExtractBorderInteger END INTERFACE INTERFACE GridResample MODULE PROCEDURE ResampleFloatCell MODULE PROCEDURE ResampleIntegerCell MODULE PROCEDURE ResampleFloat MODULE PROCEDURE ResampleInteger END INTERFACE INTERFACE CellArea MODULE PROCEDURE CellAreaFloat MODULE PROCEDURE CellAreaInteger END INTERFACE INTERFACE CellLength MODULE PROCEDURE CellLengthFloat MODULE PROCEDURE CellLengthInteger END INTERFACE INTERFACE GetArea MODULE PROCEDURE GetAreaOfGridFloat MODULE PROCEDURE GetAreaOfGridInteger END INTERFACE INTERFACE CellIsNoData MODULE PROCEDURE CellIsNoDataInteger MODULE PROCEDURE CellIsNoDataFloat END INTERFACE INTERFACE CellIsValid MODULE PROCEDURE CellIsValidInteger MODULE PROCEDURE CellIsValidFloat END INTERFACE INTERFACE Grid2vector MODULE PROCEDURE Grid2vectorInteger MODULE PROCEDURE Grid2vectorFloat END INTERFACE !global procedures: PUBLIC :: GridConvert PUBLIC :: GetXY PUBLIC :: GetIJ PUBLIC :: CRSisEqual PUBLIC :: GridByIni PUBLIC :: IsOutOfGrid PUBLIC :: ExtractBorder PUBLIC :: GridResample PUBLIC :: CellArea PUBLIC :: CellIsNoData PUBLIC :: CellIsValid PUBLIC :: Grid2vector PUBLIC :: CellLength ! Local (i.e. private) Declarations: ! Local Procedures: PRIVATE :: GridConvertFloat PRIVATE :: GridConvertInteger PRIVATE :: CRSisEqualFloatFloat PRIVATE :: CRSisEqualIntInt PRIVATE :: CRSisEqualIntFloat PRIVATE :: CRSisEqualFloatInt PRIVATE :: GetXYinteger PRIVATE :: GetXYFloat PRIVATE :: GetIJinteger PRIVATE :: GetIJFloat PRIVATE :: GridByIniFloat PRIVATE :: GridByIniInteger PRIVATE :: IsOutOfGridInteger PRIVATE :: IsOutOfGridFloat PRIVATE :: ExtractBorderFloat PRIVATE :: ExtractBorderInteger PRIVATE :: ResampleFloatCell PRIVATE :: ResampleIntegerCell PRIVATE :: ResampleFloat PRIVATE :: ResampleInteger PRIVATE :: AssignGridIntegerReal PRIVATE :: AssignGridReal PRIVATE :: AssignGridInteger PRIVATE :: AssignGridRealInteger PRIVATE :: AssignReal PRIVATE :: AssignInteger PRIVATE :: CellAreaFloat PRIVATE :: CellAreaInteger PRIVATE :: GetAreaOfGridInteger PRIVATE :: GetAreaOfGridFloat PRIVATE :: CellIsNoDataInteger PRIVATE :: CellIsNoDataFloat PRIVATE :: CellIsValidInteger PRIVATE :: CellIsValidFloat PRIVATE :: CellLengthFloat PRIVATE :: CellLengthInteger !======= CONTAINS !======= ! Define procedures contained in this module. !------------------------------------------------------------------------------ !| Description ! compute area (m2) of a cell of a grid as a function of latitude defined by ! the position of cell in local coordinate system (row, column). ! Input grid of type grid_real ! *** ! Reference: ! ! Sivakholundu, K. M., Prabaharan, N. (1998). A program to ! compute the area of an irregular polygon on a spheroidal surface, ! Computers & Geosciences, 24(8), 823-826. FUNCTION CellAreaFloat & ! (gridIn, i, j) & ! RESULT(cellarea) USE GeoLib , ONLY: & !Imported parameters: GEODETIC USE Units, ONLY: & !Imported parameters: degToRad, squareKilometer !arguments with intent(in): TYPE(grid_real), INTENT (IN) :: gridIn INTEGER, INTENT (IN) :: i,j !!row and column of cell !Local variables REAL (KIND = float) :: midLatitude !mid-latitude of cell REAL (KIND = float) :: cellWidht !cell width in angular terms REAL (KIND = float) :: re !!semi-major axis of spheroid REAL (KIND = float) :: ecc !!eccentricity of spheroid REAL (KIND = float) :: cellarea REAL (KIND = float) :: x, y LOGICAL :: check SELECT CASE (gridIn % grid_mapping % system) CASE (GEODETIC) CALL GetXY (i, j, gridIn, x, y, check) IF (.NOT. check) THEN CALL Catch ('error', 'GridOperations', & 'cell out of grid calculating cell area' ) ENDIF midLatitude = y * degToRad cellWidht = gridIn % cellsize * degToRad re = gridIn % grid_mapping % ellipsoid % a ecc = gridIn % grid_mapping % ellipsoid % e cellarea = re**2. * (1.-ecc**2.) * SIN(cellWidht)**2. * COS(midLatitude) / & (1.-ecc**2.*SIN(midLatitude)**2.)**2. CASE DEFAULT cellarea = gridIn % cellsize ** 2. END SELECT END FUNCTION CellAreaFloat !------------------------------------------------------------------------------ !| Description ! compute area (m2) of a cell of a grid as a function of latitude defined by ! the position of cell in local coordinate system (row, column). ! Input grid of type grid_integer ! *** ! Reference: ! ! Sivakholundu, K. M., Prabaharan, N. (1998). A program to ! compute the area of an irregular polygon on a spheroidal surface, ! Computers & Geosciences, 24(8), 823-826. FUNCTION CellAreaInteger & ! (gridIn, i, j) & ! RESULT(cellarea) USE GeoLib , ONLY: & !Imported parameters: GEODETIC USE Units, ONLY: & !Imported parameters: degToRad, squareKilometer !arguments with intent(in): TYPE(grid_integer), INTENT (IN) :: gridIn INTEGER, INTENT (IN) :: i,j !!row and column of cell !Local variables REAL (KIND = float) :: midLatitude !mid-latitude of cell REAL (KIND = float) :: cellWidht !cell width in angular terms REAL (KIND = float) :: re !!semi-major axis of spheroid REAL (KIND = float) :: ecc !!eccentricity of spheroid REAL (KIND = float) :: cellarea REAL (KIND = float) :: x, y LOGICAL :: check !------------------------------end of declarations----------------------------- SELECT CASE (gridIn % grid_mapping % system) CASE (GEODETIC) CALL GetXY (i, j, gridIn, x, y, check) IF (.NOT. check) THEN CALL Catch ('error', 'GridOperations', & 'cell out of grid calculating cell area' ) ENDIF midLatitude = y * degToRad cellWidht = gridIn % cellsize * degToRad re = gridIn % grid_mapping % ellipsoid % a ecc = gridIn % grid_mapping % ellipsoid % e cellarea = re**2. * (1.-ecc**2.) * SIN(cellWidht)**2. * COS(midLatitude) / & (1.-ecc**2.*SIN(midLatitude)**2.)**2. CASE DEFAULT cellarea = gridIn % cellsize ** 2. END SELECT END FUNCTION CellAreaInteger !------------------------------------------------------------------------------ !| Description ! compute average length (m) of a cell of a grid as the squareroot of area ! Input grid of type grid_integer FUNCTION CellLengthInteger & ! (gridIn, i, j) & ! RESULT(length) !arguments with intent(in): TYPE(grid_integer), INTENT (IN) :: gridIn INTEGER, INTENT (IN) :: i,j !!row and column of cell !Local variables REAL (KIND = float) :: length !------------------------------end of declarations----------------------------- length = ( CellArea (gridin,i,j) ) ** 0.5 RETURN END FUNCTION CellLengthInteger !------------------------------------------------------------------------------ !| Description ! compute average length (m) of a cell of a grid as the squareroot of area ! Input grid of type grid_real FUNCTION CellLengthFloat & ! (gridIn, i, j) & ! RESULT(length) !arguments with intent(in): TYPE(grid_real), INTENT (IN) :: gridIn INTEGER, INTENT (IN) :: i,j !!row and column of cell !Local variables REAL (KIND = float) :: length !------------------------------end of declarations----------------------------- length = ( CellArea (gridin,i,j) ) ** 0.5 RETURN END FUNCTION CellLengthFloat !============================================================================== !| Description: ! coordinate conversion of a `grid_real` ! definition of corner points: ! !``` ! A---------B ! | | ! | | ! | | ! C---------D !``` SUBROUTINE GridConvertFloat & ! (GridIn, GridOut, cellsize) USE GeoLib, ONLY: & !Imported type definitions: Coordinate, & ! Imported routines: SetCoord, Convert, ASSIGNMENT(=) !arguments with intent(in): TYPE (grid_real), INTENT (IN) :: GridIn REAL (KIND = float), OPTIONAL, INTENT (IN) :: cellsize !arguments with intent (inout): TYPE (grid_real), INTENT (INOUT) :: GridOut !local variables: TYPE (Coordinate) :: Ain, Bin, Cin, Din !!corner points of input grid TYPE (Coordinate) :: Aout, Bout, Cout, Dout !!corner points converted to new CRS TYPE (Coordinate) :: Arec, Brec, Crec, Drec !!corner points of rectangle TYPE (Coordinate) :: pointNew !!generic point in the new CRS TYPE (Coordinate) :: pointOld !!generic point in the old CRS REAL (KIND = float) :: Xdim, Ydim INTEGER :: newXsize, newYsize REAL (KIND = float) :: CellSizeX, CellSizeY, newCellSize INTEGER (KIND = short) :: ios !!error return code INTEGER (KIND = short) :: i, j, iOld, jOld REAL (KIND = float) :: X, Y LOGICAL :: checkBound !------------end of declaration------------------------------------------------ !------------------------------------------------------------------------------ ! calculate corner points !------------------------------------------------------------------------------ !Set coordinate of corner Ain CALL SetCoord (GridIn % xllcorner , GridIn % yllcorner + & GridIn % idim * GridIn % cellsize, Ain) !copy coordinate reference system parameters Ain % system = GridIn % grid_mapping Aout %system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Ain, Aout) !Set coordinate of corner Bin CALL SetCoord (GridIn % xllcorner + GridIn % jdim * GridIn % cellsize , & GridIn % yllcorner + GridIn % idim * GridIn % cellsize, Bin) !copy corrdinate reference system parameters Bin % system = GridIn % grid_mapping Bout % system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Bin, Bout) !Set coordinate of corner Cin CALL SetCoord (GridIn % xllcorner, GridIn % yllcorner, Cin) !copy coordinate reference system parameters Cin % system = GridIn % grid_mapping Cout % system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Cin, Cout) !Set coordinate of corner Din CALL SetCoord (GridIn % xllcorner + GridIn % jdim * GridIn % cellsize, & GridIn % yllcorner, Din) !copy corrdinate reference system parameters Din % system = GridIn % grid_mapping Dout % system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Din, Dout) !------------------------------------------------------------------------------ ! define minimum rectangular view that contains the 4 converted points !------------------------------------------------------------------------------ !calculate Arec CALL SetCoord ( MIN (Aout % easting, Cout % easting), & MAX (Aout % northing, Bout % northing), Arec ) !copy corrdinate reference system parameters Arec % system = Aout % system !calculate Brec CALL SetCoord ( MAX (Bout % easting, Dout % easting), & MAX (Aout % northing, Bout % northing), Brec ) !copy corrdinate reference system parameters Brec % system = Bout % system !calculate Crec CALL SetCoord ( MIN (Aout % easting, Cout % easting), & MIN (Cout % northing, Dout % northing), Crec ) !copy corrdinate reference system parameters Crec % system = Cout % system !calculate Drec CALL SetCoord ( MAX (Bout % easting, Dout % easting), & MIN (Cout % northing, Dout % northing), Drec ) !copy corrdinate reference system parameters Drec % system = Dout % system !------------------------------------------------------------------------------ ! calculate cellsize of gridout, number of rows and columns !------------------------------------------------------------------------------ Xdim = Brec % easting - Arec % easting Ydim = Brec % northing - Drec % northing IF (PRESENT (cellsize) ) THEN !set cellsize of new grid to cellsize newCellSize = cellsize !calculate number of columns of new grid newXsize = INT ( Xdim / newCellSize ) + 1 !calculate number of rows of new grid newYsize = INT ( Ydim / newCellSize ) + 1 ELSE CellSizeX = Xdim / GridIn % jdim CellSizeY = Ydim / GridIn % idim !set cellsize of new grid to CellSizeX newCellSize = CellSizeX !set number of columns of new grid equals to GridIn newXsize = GridIn % jdim !calculate number of rows of new grid newYsize = INT ( Ydim / newCellSize ) + 1 END IF !------------------------------------------------------------------------------ ! define new grid !------------------------------------------------------------------------------ GridOut % jdim = newXsize GridOut % idim = newYsize GridOut % standard_name = GridIn % standard_name GridOut % long_name = GridIn % long_name GridOut % units = GridIn % units GridOut % varying_mode = GridIn % varying_mode GridOut % nodata = GridIn % nodata GridOut % valid_min = GridIn % valid_min GridOut % valid_max = GridIn % valid_max GridOut % reference_time = GridIn % reference_time GridOut % current_time = GridIn % current_time GridOut % time_index = GridIn % time_index GridOut % time_unit = GridIn % time_unit GridOut % cellsize = newCellSize GridOut % xllcorner = Crec % easting GridOut % yllcorner = Crec % northing !esri_pe_string !!used by ArcMap 9.2 IF (ALLOCATED(GridOut % mat)) THEN DEALLOCATE (GridOut % mat) END IF ALLOCATE ( GridOut % mat ( newYsize, newXsize ), STAT = ios ) IF (ios /= 0) THEN CALL Catch ('error', 'GridOperations', & 'memory allocation: ', & code = memAllocError,argument = 'converted grid' ) ENDIF DO i = 1, GridOut % idim DO j = 1, GridOut % jdim GridOut % mat (i,j) = GridOut % nodata END DO END DO !------------------------------------------------------------------------------ ! fill in new grid with values !------------------------------------------------------------------------------ !set CRS of pointOld and pointNew pointOld % system = GridIn % grid_mapping pointNew % system = GridOut % grid_mapping !loop DO i = 1, GridOut % idim DO j = 1, GridOut % jdim !set pointNew CALL GetXY (i, j, GridOut, X, Y, checkBound) CALL SetCoord (X, Y, pointNew) !calculate pointOld CALL Convert (pointNew, pointOld) CALL GetIJ (pointOld % easting, pointOld % northing, GridIn, iOld, jOld, checkBound) IF (checkBound) THEN IF (GridIn % mat (iOld, jOld) /= GridIn % nodata) THEN GridOut % mat (i,j) = GridIn % mat (iOld, jOld) END IF END IF END DO END DO END SUBROUTINE GridConvertFloat !============================================================================== !| Description: ! coordinate conversion of a `grid_integer` ! definition of corner points: ! !``` ! A---------B ! | | ! | | ! | | ! C---------D !``` ! SUBROUTINE GridConvertInteger & ! (GridIn, GridOut, cellsize) USE GeoLib, ONLY: & !Imported type definitions: Coordinate, & ! Imported routines: SetCoord, Convert, ASSIGNMENT(=) !arguments with intent(in): TYPE (grid_integer), INTENT (IN) :: GridIn REAL (KIND = float), OPTIONAL, INTENT (IN) :: cellsize !arguments with intent (inout): TYPE (grid_integer), INTENT (INOUT) :: GridOut !local variables: TYPE (Coordinate) :: Ain, Bin, Cin, Din !!corner points of input grid TYPE (Coordinate) :: Aout, Bout, Cout, Dout !!corner points converted to new CRS TYPE (Coordinate) :: Arec, Brec, Crec, Drec !!corner points of rectangle TYPE (Coordinate) :: pointNew !!generic point in the new CRS TYPE (Coordinate) :: pointOld !!generic point in the old CRS REAL (KIND = float) :: Xdim, Ydim INTEGER :: newXsize, newYsize REAL (KIND = float) :: CellSizeX, CellSizeY, newCellSize INTEGER (KIND = short) :: ios !!error return code INTEGER (KIND = short) :: i, j, iOld, jOld REAL (KIND = float) :: X, Y LOGICAL :: checkBound !------------end of declaration------------------------------------------------ !------------------------------------------------------------------------------ ! calculate corner points !------------------------------------------------------------------------------ !Set coordinate of corner Ain CALL SetCoord (GridIn % xllcorner , GridIn % yllcorner + & GridIn % idim * GridIn % cellsize, Ain) !copy corrdinate reference system parameters Ain % system = GridIn % grid_mapping Aout %system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Ain, Aout) !Set coordinate of corner Bin CALL SetCoord (GridIn % xllcorner + GridIn % jdim * GridIn % cellsize , & GridIn % yllcorner + GridIn % idim * GridIn % cellsize, Bin) !copy corrdinate reference system parameters Bin % system = GridIn % grid_mapping Bout %system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Bin, Bout) !Set coordinate of corner Cin CALL SetCoord (GridIn % xllcorner, GridIn % yllcorner, Cin) !copy corrdinate reference system parameters Cin % system = GridIn % grid_mapping Cout %system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Cin, Cout) !Set coordinate of corner Din CALL SetCoord (GridIn % xllcorner + GridIn % jdim * GridIn % cellsize, & GridIn % yllcorner, Din) !copy corrdinate reference system parameters Din % system = GridIn % grid_mapping Dout % system = GridOut % grid_mapping !calculate coordinate in the new reference system CALL Convert (Din, Dout) !------------------------------------------------------------------------------ ! define minimum rectangular view that contains the 4 converted points !------------------------------------------------------------------------------ !calculate Arec CALL SetCoord ( MIN (Aout % easting, Cout % easting), & MAX (Aout % northing, Bout % northing), Arec ) !copy corrdinate reference system parameters Arec % system = Aout % system !calculate Brec CALL SetCoord ( MAX (Bout % easting, Dout % easting), & MAX (Aout % northing, Bout % northing), Brec ) !copy corrdinate reference system parameters Brec % system = Bout % system !calculate Crec CALL SetCoord ( MIN (Aout % easting, Cout % easting), & MIN (Cout % northing, Dout % northing), Crec ) !copy corrdinate reference system parameters Crec % system = Cout % system !calculate Drec CALL SetCoord ( MAX (Bout % easting, Dout % easting), & MIN (Cout % northing, Dout % northing), Drec ) !copy corrdinate reference system parameters Drec % system = Dout % system !------------------------------------------------------------------------------ ! calculate cellsize of gridout, number of rows and columns !------------------------------------------------------------------------------ Xdim = Brec % easting - Arec % easting Ydim = Brec % northing - Drec % northing IF (PRESENT (cellsize) ) THEN !set cellsize of new grid to cellsize newCellSize = cellsize !calculate number of columns of new grid newXsize = INT ( Xdim / newCellSize ) + 1 !calculate number of rows of new grid newYsize = INT ( Ydim / newCellSize ) + 1 ELSE CellSizeX = Xdim / GridIn % jdim CellSizeY = Ydim / GridIn % idim !set cellsize of new grid to CellSizeX newCellSize = CellSizeX !set number of columns of new grid equals to GridIn newXsize = GridIn % jdim !calculate number of rows of new grid newYsize = INT ( Ydim / newCellSize ) + 1 END IF !------------------------------------------------------------------------------ ! define new grid !------------------------------------------------------------------------------ GridOut % jdim = newXsize GridOut % idim = newYsize GridOut % standard_name = GridIn % standard_name GridOut % long_name = GridIn % long_name GridOut % units = GridIn % units GridOut % varying_mode = GridIn % varying_mode GridOut % nodata = GridIn % nodata GridOut % valid_min = GridIn % valid_min GridOut % valid_max = GridIn % valid_max GridOut % reference_time = GridIn % reference_time GridOut % current_time = GridIn % current_time GridOut % time_index = GridIn % time_index GridOut % time_unit = GridIn % time_unit GridOut % cellsize = newCellSize GridOut % xllcorner = Crec % easting GridOut % yllcorner = Crec % northing !esri_pe_string !!used by ArcMap 9.2 IF (ALLOCATED(GridOut % mat)) THEN DEALLOCATE (GridOut % mat) END IF ALLOCATE ( GridOut % mat ( newYsize, newXsize ), STAT = ios ) IF (ios /= 0) THEN CALL Catch ('error', 'GridOperations', & 'memory allocation ', & code = memAllocError,argument = 'converted grid' ) ENDIF DO i = 1, GridOut % idim DO j = 1, GridOut % jdim GridOut % mat (i,j) = GridOut % nodata END DO END DO !------------------------------------------------------------------------------ ! fill in new grid with values !------------------------------------------------------------------------------ !set CRS of pointOld and pointNew pointOld % system = GridIn % grid_mapping pointNew % system = GridOut % grid_mapping !loop DO i = 1, GridOut % idim DO j = 1, GridOut % jdim !set pointNew CALL GetXY (i, j, GridOut, X, Y, checkBound) CALL SetCoord (X, Y, pointNew) !calculate pointOld CALL Convert (pointNew, pointOld) CALL GetIJ (pointOld % easting, pointOld % northing, GridIn, iOld, jOld, checkBound) IF (checkBound) THEN IF (GridIn % mat (iOld, jOld) /= GridIn % nodata) THEN GridOut % mat (i,j) = GridIn % mat (iOld, jOld) END IF END IF END DO END DO END SUBROUTINE GridConvertInteger !============================================================================== !| Description: ! returns X and Y coordinate given i and j position in grid(i,j) SUBROUTINE GetIJfloat & ! (X, Y, grid, i, j, check) IMPLICIT NONE !Arguments with intent(in): REAL (KIND = float), INTENT(IN) :: X,Y TYPE (grid_real), INTENT(IN) :: grid !Arguments with intent(out): INTEGER, INTENT(OUT) :: i, j LOGICAL, OPTIONAL, INTENT(OUT) :: check !!return false if i and j are outside grid definition !------------end of declaration------------------------------------------------ j = INT ( (X - grid % xllcorner) / grid %cellsize ) + 1 i = INT ( (grid % yllcorner + grid % idim * grid % cellsize - y) & / grid%cellsize ) + 1 IF (PRESENT (check)) THEN IF (i < 1 .OR. i > grid % idim .OR. j < 1 .OR. j > grid % jdim ) THEN check = .FALSE. ELSE check = .TRUE. END IF END IF END SUBROUTINE GetIJfloat !============================================================================== !| Description: ! returns X and Y coordinate given i and j position in grid(i,j) SUBROUTINE GetIJinteger & ! (X, Y, grid, i, j, check) IMPLICIT NONE !Arguments with intent(in): REAL (KIND = float), INTENT(IN) :: X,Y TYPE (grid_integer), INTENT(IN) :: grid !Arguments with intent(out): INTEGER, INTENT(OUT) :: i, j LOGICAL, OPTIONAL, INTENT(OUT) :: check !!return false if i and j are outside grid definition !------------end of declaration------------------------------------------------ j = INT ( (X - grid % xllcorner) / grid %cellsize ) + 1 i = INT ( (grid % yllcorner + grid % idim * grid % cellsize - y) & / grid%cellsize ) + 1 IF (PRESENT (check)) THEN IF (i < 1 .OR. i > grid % idim .OR. j < 1 .OR. j > grid % jdim ) THEN check = .FALSE. ELSE check = .TRUE. END IF END IF END SUBROUTINE GetIJinteger !============================================================================== !| Description: ! returns X and Y coordinate given i and j position in grid(i,j) SUBROUTINE GetXYfloat & ! (i, j, grid, X, Y, check) IMPLICIT NONE !Arguments with intent(in): TYPE (grid_real), INTENT(IN) :: grid INTEGER, INTENT(IN) :: i, j !Arguments with intent(out): REAL (KIND = float), INTENT(OUT) :: X,Y LOGICAL, OPTIONAL, INTENT(OUT) :: check !!return false if i and j are outside grid definition !------------end of declaration------------------------------------------------ IF (i < 1 .OR. i > grid % idim .OR. j < 1 .OR. j > grid % jdim ) THEN X = 0. Y = 0. IF ( PRESENT(check) ) check = .FALSE. ELSE X = grid % xllcorner + (j - 0.5) * grid % cellsize Y = grid % yllcorner + (grid % idim - i + 0.5) * grid % cellsize IF ( PRESENT(check) ) check = .TRUE. END IF END SUBROUTINE GetXYfloat !============================================================================== !| Description: ! returns X and Y coordinate given i and j position in grid(i,j) SUBROUTINE GetXYinteger & ! (i, j, grid, X, Y, check) IMPLICIT NONE !Arguments with intent(in): TYPE (grid_integer), INTENT(IN) :: grid INTEGER, INTENT(IN) :: i, j !Arguments with intent(out): REAL (KIND = float), INTENT(OUT) :: X,Y LOGICAL, OPTIONAL, INTENT(OUT) :: check !!return false if i and j are outside grid definition !------------end of declaration------------------------------------------------ IF (i < 1 .OR. i > grid % idim .OR. j < 1 .OR. j > grid % jdim ) THEN X = 0. Y = 0. IF ( PRESENT(check) ) check = .FALSE. ELSE X = grid % xllcorner + (j - 0.5) * grid % cellsize Y = grid % yllcorner + (grid % idim - i + 0.5) * grid % cellsize IF ( PRESENT(check) ) check = .TRUE. END IF END SUBROUTINE GetXYinteger !============================================================================== !| Description: ! return `.TRUE.` if the two grids have the same Coordinate Reference System, ! and the same spatial reference (cellsize, xllxorner, yllcorner, idim, jdim) ! If checkCells is given the function checks that grid has ! the same active cells of mask. FUNCTION CRSisEqualFloatFloat & ! (mask, grid, checkCells) & ! RESULT (isEqual) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_real), INTENT(IN) :: mask, grid LOGICAL, OPTIONAL, INTENT(IN) :: checkCells !Local declarations: LOGICAL :: isEqual INTEGER :: i,j !------------------------end of declaration------------------------------------ IF ( mask % grid_mapping == grid % grid_mapping .AND. & mask % cellsize == grid % cellsize .AND. & mask % xllcorner == grid % xllcorner .AND. & mask % yllcorner == grid % yllcorner .AND. & mask % idim == grid % idim .AND. & mask % jdim == grid % jdim ) THEN isEqual = .TRUE. ELSE isEqual = .FALSE. END IF IF ( PRESENT (checkCells) ) THEN IF (checkCells) THEN DO i = 1, mask % idim DO j = 1, mask % jdim IF ( mask % mat (i,j) /= mask % nodata .AND. & grid % mat (i,j) == grid % nodata ) THEN isEqual = .FALSE. EXIT END IF END DO END DO END IF END IF END FUNCTION CRSisEqualFloatFloat !============================================================================== !| Description: ! return `.TRUE.` if the two grids have the same Coordinate Reference System, ! and the same spatial reference (cellsize, xllxorner, yllcorner, idim, jdim) ! If `checkCells` is given the function checks that grid has ! the same active cells of mask. FUNCTION CRSisEqualIntInt & ! (mask, grid, checkCells) & ! RESULT (isEqual) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_integer), INTENT(IN) :: mask, grid LOGICAL, OPTIONAL, INTENT(IN) :: checkCells !Local declarations: LOGICAL :: isEqual INTEGER :: i,j !------------------------end of declaration------------------------------------ IF ( mask % grid_mapping == grid % grid_mapping .AND. & mask % cellsize == grid % cellsize .AND. & mask % xllcorner == grid % xllcorner .AND. & mask % yllcorner == grid % yllcorner .AND. & mask % idim == grid % idim .AND. & mask % jdim == grid % jdim ) THEN isEqual = .TRUE. ELSE isEqual = .FALSE. END IF IF ( PRESENT (checkCells) ) THEN IF (checkCells) THEN DO i = 1, mask % idim DO j = 1, mask % jdim IF ( mask % mat (i,j) /= mask % nodata .AND. & grid % mat (i,j) == grid % nodata ) THEN isEqual = .FALSE. EXIT END IF END DO END DO END IF END IF END FUNCTION CRSisEqualIntInt !============================================================================== !| Description: ! return `.TRUE.` if the two grids have the same Coordinate Reference System, ! and the same spatial reference (cellsize, xllxorner, yllcorner, idim, jdim) ! If `checkCells` is given the function checks that grid has ! the same active cells of mask. FUNCTION CRSisEqualFloatInt & ! (mask, grid, checkCells) & ! RESULT (isEqual) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_real), INTENT(IN) :: mask TYPE (grid_integer), INTENT(IN) :: grid LOGICAL, OPTIONAL, INTENT(IN) :: checkCells !Local declarations: LOGICAL :: isEqual INTEGER :: i,j !------------------------end of declaration------------------------------------ IF ( mask % grid_mapping == grid % grid_mapping .AND. & mask % cellsize == grid % cellsize .AND. & mask % xllcorner == grid % xllcorner .AND. & mask % yllcorner == grid % yllcorner .AND. & mask % idim == grid % idim .AND. & mask % jdim == grid % jdim ) THEN isEqual = .TRUE. ELSE isEqual = .FALSE. END IF IF ( PRESENT (checkCells) ) THEN IF (checkCells) THEN DO i = 1, mask % idim DO j = 1, mask % jdim IF ( mask % mat (i,j) /= mask % nodata .AND. & grid % mat (i,j) == grid % nodata ) THEN isEqual = .FALSE. EXIT END IF END DO END DO END IF END IF END FUNCTION CRSisEqualFloatInt !============================================================================== !| Description: ! return `.TRUE.` if the two grids have the same Coordinate Reference System, ! and the same spatial reference (cellsize, xllxorner, yllcorner, idim, jdim) ! If `checkCells` is given the function checks that grid has ! the same active cells of mask. FUNCTION CRSisEqualIntFloat & ! (mask, grid, checkCells) & ! RESULT (isEqual) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_real), INTENT(IN) :: grid TYPE (grid_integer), INTENT(IN) :: mask LOGICAL, OPTIONAL, INTENT(IN) :: checkCells !Local declarations: LOGICAL :: isEqual INTEGER :: i,j !------------------------end of declaration------------------------------------ IF ( mask % grid_mapping == grid % grid_mapping .AND. & mask % cellsize == grid % cellsize .AND. & mask % xllcorner == grid % xllcorner .AND. & mask % yllcorner == grid % yllcorner .AND. & mask % idim == grid % idim .AND. & mask % jdim == grid % jdim ) THEN isEqual = .TRUE. ELSE isEqual = .FALSE. END IF IF ( PRESENT (checkCells) ) THEN IF (checkCells) THEN DO i = 1, mask % idim DO j = 1, mask % jdim IF ( mask % mat (i,j) /= mask % nodata .AND. & grid % mat (i,j) == grid % nodata ) THEN isEqual = .FALSE. EXIT END IF END DO END DO END IF END IF END FUNCTION CRSisEqualIntFloat !============================================================================== !| Description: ! read a `grid_real` using information stored in ini configuration file SUBROUTINE GridByIniFloat & ! (ini, grid, section, time) USE Inilib, ONLY: & !Imported type definitions: IniList, & !imported routines: IniReadString, IniReadReal, KeyIsPresent, IniReadReal, IniReadInt USE StringManipulation, ONLY: & !Imported routines: StringToUpper, StringToLower, StringToShort USE Chronos, ONLY: & !Imported type definitions: DateTime, & !Imported operands: ASSIGNMENT( = ) USE GeoLib , ONLY: & !Imported routines: DecodeEPSG !SetCRS, ScanDatum, & !SetGeodeticParameters, SetTransverseMercatorParameters, & !SetSwissParameters, & !Imported parameters: !GEODETIC, TM, SOC, & !EAST, WEST, NORTH, SOUTH, ROME40 USE Units, ONLY: & !Imported parameters: degToRad IMPLICIT NONE !arguments with intent in: TYPE (IniList), INTENT(IN) :: ini CHARACTER (LEN = *), INTENT (IN) :: section TYPE (DateTime), OPTIONAL, INTENT (IN) :: time !arguments with intent out: TYPE (grid_real), INTENT (OUT) :: grid !local variables: CHARACTER (LEN = 100) :: fileFormat CHARACTER (LEN = 300) :: file CHARACTER (LEN = 100) :: variable !!variable to read CHARACTER (LEN = 100) :: stdName !!standard name of the variable to read !CHARACTER (LEN = 100) :: grid_mapping INTEGER :: epsg INTEGER ( KIND = short) :: timeSync !CHARACTER (LEN = 100) :: datum TYPE (DateTime) :: gridTime !!time of the grid to read REAL (KIND = float) :: scale_factor REAL (KIND = float) :: offset REAL (KIND = float) :: valid_min REAL (KIND = float) :: valid_max REAL (KIND = float) :: centralMeridian !INTEGER :: grid_datum !INTEGER (KIND = short) :: utm_zone INTEGER :: i,j !-----------------------------end of declaration------------------------------- file = IniReadString ('file', ini, section) IF (KeyIsPresent ('format', ini, section)) THEN fileFormat = StringToUpper ( IniReadString ('format', ini, section) ) ELSE CALL Catch ('error', 'GridOperations', & 'format not specified for grid: ', & argument = section ) END IF !read grid IF ( fileFormat == 'ESRI-ASCII' ) THEN CALL NewGrid (grid, file, ESRI_ASCII) ELSE IF (fileFormat == 'ESRI-BINARY' ) THEN CALL NewGrid (grid, file, ESRI_BINARY) ELSE IF ( fileFormat == 'NET-CDF' ) THEN IF (KeyIsPresent('variable', ini, section)) THEN variable = IniReadString ('variable', ini, section) IF (KeyIsPresent('time', ini, section)) THEN gridTime = IniReadString ('time', ini, section) CALL NewGrid (grid, file, NET_CDF, variable = variable, time = gridTime) ELSE IF (KeyIsPresent('sync-initial-time', ini, section)) THEN timeSync = IniReadInt ('sync-initial-time', ini, section) IF ( timeSync == 1) THEN CALL SyncTime ( file, time, gridTime ) CALL NewGrid (grid, file, NET_CDF, variable = variable, time = gridTime) END IF ELSE CALL NewGrid (grid, file, NET_CDF, variable = variable) END IF ELSE IF (KeyIsPresent('standard_name', ini, section)) THEN stdName = IniReadString ('standard_name', ini, section) IF (KeyIsPresent('time', ini, section)) THEN gridTime = IniReadString ('time', ini, section) CALL NewGrid (grid, file, NET_CDF, stdName = stdName, time = gridtime) ELSE CALL NewGrid (grid, file, NET_CDF, stdName = stdName) END IF ELSE CALL Catch ('error', 'GridOperations', & 'variable or standard name not defined while reading netcdf: ', & argument = section ) END IF ELSE CALL Catch ('error', 'GridOperations', & 'format not supported: ', & argument = fileFormat ) END IF !apply scale factor if given IF (KeyIsPresent ('scale_factor', ini, section) ) THEN scale_factor = IniReadReal ('scale_factor', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) * scale_factor END IF END DO END DO END IF !add offset if given IF (KeyIsPresent ('offset', ini, section) ) THEN offset = IniReadReal ('offset', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) + offset END IF END DO END DO END IF !check upper bound if given IF (KeyIsPresent ('valid_max', ini, section) ) THEN valid_max = IniReadInt ('valid_max', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) > valid_max ) THEN grid % mat (i,j) = valid_max END IF END IF END DO END DO END IF !check lower bound if given IF (KeyIsPresent ('valid_min', ini, section) ) THEN valid_min = IniReadInt ('valid_min', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) < valid_min ) THEN grid % mat (i,j) = valid_min END IF END IF END DO END DO END IF !read coordinate reference system if given IF (KeyIsPresent ('epsg', ini, section) ) THEN epsg = IniReadInt ('epsg', ini, section) grid % grid_mapping = DecodeEPSG (epsg) ELSE CALL Catch ('error', 'GridOperations', & 'epsg not specified for grid: ', & argument = section ) END IF !IF (KeyIsPresent ('grid_mapping', ini, section) ) THEN ! grid_mapping = IniReadString ('grid_mapping', ini, section) ! IF (KeyIsPresent ('datum', ini, section) ) THEN ! datum = IniReadString ('datum', ini, section) ! ELSE ! datum = 'WGS84' ! END IF ! grid_datum = ScanDatum (datum) ! !set reference system ! IF (StringToUpper(grid_mapping) == 'GEODETIC') THEN ! CALL SetCRS (GEODETIC, grid_datum, grid % grid_mapping) ! !default prime_meridian = 0. ! CALL SetGeodeticParameters (grid % grid_mapping, prime_meridian = 0.0) ! ELSE IF (StringToUpper(grid_mapping(1:11)) == 'GAUSS-BOAGA') THEN ! !gauss boaga is a particular case of transverse-mercator ! CALL SetCRS (TM, ROME40, grid % grid_mapping) ! IF (StringToUpper(grid_mapping(13:16)) == 'EAST') THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 15. * degToRad, & ! falseE = 2520000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 9. * degToRad, & ! falseE = 1500000., falseN = 0., k = 0.9996) ! END IF ! ELSE IF (StringToUpper(grid_mapping(1:3)) == 'UTM') THEN ! !UTM is a particular case of transverse-mercator ! CALL SetCRS (TM, grid_datum, grid % grid_mapping) ! utm_zone = StringToShort(grid_mapping(4:5)) ! IF ( utm_zone >= 31) THEN ! centralMeridian = (6 * utm_zone - 183) * degToRad ! ELSE ! centralMeridian = (6 * utm_zone + 177) * degToRad ! END IF ! IF (StringToUpper(grid_mapping(6:6)) == 'N' ) THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 10000000., k = 0.9996) ! END IF ! ! ELSE IF (StringToUpper(grid_mapping(1:5)) == 'SWISS') THEN ! CALL SetCRS (SOC, grid_datum, grid % grid_mapping) ! CALL SetSwissParameters & ! (grid % grid_mapping, latc = 0.819474, lonc = 0.129845, & ! azimuth = 1.570796, falseE = 600000., falseN = 200000., k = 1.) ! END IF ! !END IF !varying mode IF (KeyIsPresent ('varying_mode', ini, section) ) THEN grid % varying_mode = StringToLower(IniReadString ('varying_mode', ini, section)) !check option is valid IF (grid % varying_mode (1:8) /= 'sequence' .AND. & grid % varying_mode (1:6) /= 'linear' ) THEN CALL Catch ('error', 'GridOperations', & 'invalid varying_mode option for grid: ', & code = unknownOption, argument = section ) END IF ELSE !default to 'sequence' grid % varying_mode = 'sequence' END IF END SUBROUTINE GridByIniFloat !============================================================================== !| Description: ! read a `grid_integer` using information stored in ini configuration file SUBROUTINE GridByIniInteger & ! (ini, grid, section) USE Inilib, ONLY: & !Imported type definitions: IniList, & !imported routines: IniReadString, IniReadReal, KeyIsPresent, IniReadReal, IniReadInt USE StringManipulation, ONLY: & !Imported routines: StringToUpper, StringToLower, StringToShort USE Chronos, ONLY: & !Imported type definitions: DateTime, & !Imported operands: ASSIGNMENT( = ) USE GeoLib , ONLY: & !Imported routines: DecodeEPSG !SetCRS, ScanDatum, & !SetGeodeticParameters, SetTransverseMercatorParameters, & !SetSwissParameters, & !Imported parameters: !GEODETIC, TM, SOC, & !EAST, WEST, NORTH, SOUTH, ROME40 USE Units, ONLY: & !Imported parameters: degToRad IMPLICIT NONE !arguments with intent in: TYPE (IniList), INTENT(IN) :: ini CHARACTER (LEN = *), INTENT (IN) :: section !arguments with intent out: TYPE (grid_integer), INTENT (OUT) :: grid !local variables: CHARACTER (LEN = 100) :: fileFormat CHARACTER (LEN = 300) :: file CHARACTER (LEN = 100) :: variable !!variable to read CHARACTER (LEN = 100) :: stdName !!standard name of the variable to read INTEGER :: epsg !CHARACTER (LEN = 100) :: grid_mapping !CHARACTER (LEN = 100) :: datum TYPE (DateTime) :: gridTime !!time of the grid to read REAL (KIND = float) :: scale_factor REAL (KIND = float) :: offset INTEGER (KIND = long) :: valid_min INTEGER (KIND = long) :: valid_max !REAL (KIND = float) :: centralMeridian !INTEGER :: grid_datum !INTEGER (KIND = short) :: utm_zone INTEGER :: i,j !-----------------------------end of declaration------------------------------- file = IniReadString ('file', ini, section) IF (KeyIsPresent ('format', ini, section)) THEN fileFormat = StringToUpper ( IniReadString ('format', ini, section) ) ELSE CALL Catch ('error', 'GridOperations', & 'format not specified for grid: ', & argument = section ) END IF !read grid IF ( fileFormat == 'ESRI-ASCII' ) THEN CALL NewGrid (grid, file, ESRI_ASCII) ELSE IF (fileFormat == 'ESRI-BINARY' ) THEN CALL NewGrid (grid, file, ESRI_BINARY) ELSE IF ( fileFormat == 'NET-CDF' ) THEN IF (KeyIsPresent('variable', ini, section)) THEN variable = IniReadString ('variable', ini, section) IF (KeyIsPresent('time', ini, section)) THEN gridTime = IniReadString ('time', ini, section) CALL NewGrid (grid, file, NET_CDF, variable = variable, time = gridTime) ELSE CALL NewGrid (grid, file, NET_CDF, variable = variable) END IF ELSE IF (KeyIsPresent('standard_name', ini, section)) THEN stdName = IniReadString ('standard_name', ini, section) IF (KeyIsPresent('time', ini, section)) THEN gridTime = IniReadString ('time', ini, section) CALL NewGrid (grid, file, NET_CDF, stdName = stdName, time = gridtime) ELSE CALL NewGrid (grid, file, NET_CDF, stdName = stdName) END IF ELSE CALL Catch ('error', 'GridOperations', & 'variable or standard name not defined while reading netcdf: ', & argument = section ) END IF ELSE CALL Catch ('error', 'GridOperations', & 'format not supported: ', & argument = fileFormat ) END IF !apply scale factor if given IF (KeyIsPresent ('scale_factor', ini, section) ) THEN scale_factor = IniReadReal ('scale_factor', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) * scale_factor END IF END DO END DO END IF !add offset if given IF (KeyIsPresent ('offset', ini, section) ) THEN offset = IniReadReal ('offset', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) + offset END IF END DO END DO END IF !check upper bound if given IF (KeyIsPresent ('valid_max', ini, section) ) THEN valid_max = IniReadInt ('valid_max', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) > valid_max ) THEN grid % mat (i,j) = valid_max END IF END IF END DO END DO END IF !check lower bound if given IF (KeyIsPresent ('valid_min', ini, section) ) THEN valid_min = IniReadInt ('valid_min', ini, section) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) < valid_min ) THEN grid % mat (i,j) = valid_min END IF END IF END DO END DO END IF !read coordinate reference system if given IF (KeyIsPresent ('epsg', ini, section) ) THEN epsg = IniReadInt ('epsg', ini, section) grid % grid_mapping = DecodeEPSG (epsg) ELSE CALL Catch ('error', 'GridOperations', & 'epsg not specified for grid: ', & argument = section ) END IF !IF (KeyIsPresent ('grid_mapping', ini, section) ) THEN ! grid_mapping = IniReadString ('grid_mapping', ini, section) ! IF (KeyIsPresent ('datum', ini, section) ) THEN ! datum = IniReadString ('datum', ini, section) ! ELSE ! datum = 'WGS84' ! END IF ! grid_datum = ScanDatum (datum) ! !set reference system ! IF (StringToUpper(grid_mapping) == 'GEODETIC') THEN ! CALL SetCRS (GEODETIC, grid_datum, grid % grid_mapping) ! !default prime_meridian = 0. ! CALL SetGeodeticParameters (grid % grid_mapping, prime_meridian = 0.0) ! ELSE IF (StringToUpper(grid_mapping(1:11)) == 'GAUSS-BOAGA') THEN ! !gauss boaga is a particular case of transverse-mercator ! CALL SetCRS (TM, ROME40, grid % grid_mapping) ! IF (StringToUpper(grid_mapping(13:16)) == 'EAST') THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 15. * degToRad, & ! falseE = 2520000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 9. * degToRad, & ! falseE = 1500000., falseN = 0., k = 0.9996) ! END IF ! ELSE IF (StringToUpper(grid_mapping(1:3)) == 'UTM') THEN ! !UTM is a particular case of transverse-mercator ! CALL SetCRS (TM, grid_datum, grid % grid_mapping) ! utm_zone = StringToShort(grid_mapping(4:5)) ! IF ( utm_zone >= 31) THEN ! centralMeridian = (6 * utm_zone - 183) * degToRad ! ELSE ! centralMeridian = (6 * utm_zone + 177) * degToRad ! END IF ! IF (StringToUpper(grid_mapping(6:6)) == 'N' ) THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 10000000., k = 0.9996) ! END IF ! ! ELSE IF (StringToUpper(grid_mapping(1:5)) == 'SWISS') THEN ! CALL SetCRS (SOC, grid_datum, grid % grid_mapping) ! CALL SetSwissParameters & ! (grid % grid_mapping, latc = 0.819474, lonc = 0.129845, & ! azimuth = 1.570796, falseE = 600000., falseN = 200000., k = 1.) ! END IF ! !END IF ! !varying mode IF (KeyIsPresent ('varying_mode', ini, section) ) THEN grid % varying_mode = StringToLower(IniReadString ('varying_mode', ini, section)) !check option is valid IF (grid % varying_mode /= 'sequence' .OR. & grid % varying_mode /= 'linear' ) THEN CALL Catch ('error', 'GridOperations', & 'invalid varying_mode option for grid: ', & code = unknownOption, argument = section ) END IF ELSE !default to 'sequence' grid % varying_mode = 'sequence' END IF END SUBROUTINE GridByIniInteger !============================================================================== !| Description: ! read a `grid_real` using information stored in ini configuration file ! defined in subsection `[[...]]` SUBROUTINE GridByIniFloatSubSection & ! (ini, grid, section, subsection) USE Inilib, ONLY: & !Imported type definitions: IniList, & !imported routines: IniReadString, IniReadReal, KeyIsPresent, IniReadReal, IniReadInt USE StringManipulation, ONLY: & !Imported routines: StringToUpper, StringToShort USE Chronos, ONLY: & !Imported type definitions: DateTime, & !Imported operands: ASSIGNMENT( = ) USE GeoLib , ONLY: & !Imported routines: DecodeEPSG !SetCRS, ScanDatum, & !SetGeodeticParameters, SetTransverseMercatorParameters, & !SetSwissParameters, & !Imported parameters: !GEODETIC, TM, SOC, & !EAST, WEST, NORTH, SOUTH, ROME40 USE Units, ONLY: & !Imported parameters: degToRad IMPLICIT NONE !arguments with intent in: TYPE (IniList), INTENT(IN) :: ini CHARACTER (LEN = *), INTENT (IN) :: section CHARACTER (LEN = *), INTENT (IN) :: subsection !arguments with intent out: TYPE (grid_real), INTENT (OUT) :: grid !local variables: CHARACTER (LEN = 100) :: fileFormat CHARACTER (LEN = 300) :: file CHARACTER (LEN = 100) :: variable !!variable to read CHARACTER (LEN = 100) :: stdName !!standard name of the variable to read INTEGER :: epsg !CHARACTER (LEN = 100) :: grid_mapping !CHARACTER (LEN = 100) :: datum TYPE (DateTime) :: gridTime !!time of the grid to read REAL (KIND = float) :: scale_factor REAL (KIND = float) :: offset REAL (KIND = float) :: valid_min REAL (KIND = float) :: valid_max !REAL (KIND = float) :: centralMeridian !INTEGER :: grid_datum !INTEGER (KIND = short) :: utm_zone INTEGER :: i,j !-----------------------------end of declaration------------------------------- file = IniReadString ('file', ini, section, subsection) IF (KeyIsPresent ('format', ini, section, subsection)) THEN fileFormat = StringToUpper ( IniReadString ('format', ini, section, subsection) ) ELSE CALL Catch ('error', 'GridOperations', & 'format not specified for grid: ', & argument = subsection ) END IF !read grid IF ( fileFormat == 'ESRI-ASCII' ) THEN CALL NewGrid (grid, file, ESRI_ASCII) ELSE IF (fileFormat == 'ESRI-BINARY' ) THEN CALL NewGrid (grid, file, ESRI_BINARY) ELSE IF ( fileFormat == 'NET-CDF' ) THEN IF (KeyIsPresent('variable', ini, section, subsection)) THEN variable = IniReadString ('variable', ini, section, subsection) IF (KeyIsPresent('time', ini, section, subsection)) THEN gridTime = IniReadString ('time', ini, section, subsection) CALL NewGrid (grid, file, NET_CDF, variable = variable, time = gridTime) ELSE CALL NewGrid (grid, file, NET_CDF, variable = variable) END IF ELSE IF (KeyIsPresent('standard_name', ini, section, subsection)) THEN stdName = IniReadString ('standard_name', ini, section, subsection) IF (KeyIsPresent('time', ini, section, subsection)) THEN gridTime = IniReadString ('time', ini, section, subsection) CALL NewGrid (grid, file, NET_CDF, stdName = stdName, time = gridtime) ELSE CALL NewGrid (grid, file, NET_CDF, stdName = stdName) END IF ELSE CALL Catch ('error', 'GridOperations', & 'variable or standard name not defined while reading netcdf: ', & argument = subsection ) END IF ELSE CALL Catch ('error', 'GridOperations', & 'format not supported: ', & argument = fileFormat ) END IF !apply scale factor if given IF (KeyIsPresent ('scale_factor', ini, section, subsection) ) THEN scale_factor = IniReadReal ('scale_factor', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) * scale_factor END IF END DO END DO END IF !add offset if given IF (KeyIsPresent ('offset', ini, section, subsection) ) THEN offset = IniReadReal ('offset', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) + offset END IF END DO END DO END IF !check upper bound if given IF (KeyIsPresent ('valid_max', ini, section, subsection) ) THEN valid_max = IniReadInt ('valid_max', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) > valid_max ) THEN grid % mat (i,j) = valid_max END IF END IF END DO END DO END IF !check lower bound if given IF (KeyIsPresent ('valid_min', ini, section, subsection) ) THEN valid_min = IniReadInt ('valid_min', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) < valid_min ) THEN grid % mat (i,j) = valid_min END IF END IF END DO END DO END IF !read coordinate reference system if given IF (KeyIsPresent ('epsg', ini, section, subsection) ) THEN epsg = IniReadInt ('epsg', ini, section, subsection) grid % grid_mapping = DecodeEPSG (epsg) ELSE CALL Catch ('error', 'GridOperations', & 'epsg not specified for grid: ', & argument = subsection ) END IF !IF (KeyIsPresent ('grid_mapping', ini, section, subsection) ) THEN ! grid_mapping = IniReadString ('grid_mapping', ini, section, subsection) ! IF (KeyIsPresent ('datum', ini, section, subsection) ) THEN ! datum = IniReadString ('datum', ini, section, subsection) ! ELSE ! datum = 'WGS84' ! END IF ! grid_datum = ScanDatum (datum) ! !set reference system ! IF (StringToUpper(grid_mapping) == 'GEODETIC') THEN ! CALL SetCRS (GEODETIC, grid_datum, grid % grid_mapping) ! !default prime_meridian = 0. ! CALL SetGeodeticParameters (grid % grid_mapping, prime_meridian = 0.0) ! ELSE IF (StringToUpper(grid_mapping(1:11)) == 'GAUSS-BOAGA') THEN ! !gauss boaga is a particular case of transverse-mercator ! CALL SetCRS (TM, ROME40, grid % grid_mapping) ! IF (StringToUpper(grid_mapping(13:16)) == 'EAST') THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 15. * degToRad, & ! falseE = 2520000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 9. * degToRad, & ! falseE = 1500000., falseN = 0., k = 0.9996) ! END IF ! ELSE IF (StringToUpper(grid_mapping(1:3)) == 'UTM') THEN ! !UTM is a particular case of transverse-mercator ! CALL SetCRS (TM, grid_datum, grid % grid_mapping) ! utm_zone = StringToShort(grid_mapping(4:5)) ! IF ( utm_zone >= 31) THEN ! centralMeridian = (6 * utm_zone - 183) * degToRad ! ELSE ! centralMeridian = (6 * utm_zone + 177) * degToRad ! END IF ! IF (StringToUpper(grid_mapping(6:6)) == 'N' ) THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 10000000., k = 0.9996) ! END IF ! ! ELSE IF (StringToUpper(grid_mapping(1:5)) == 'SWISS') THEN ! CALL SetCRS (SOC, grid_datum, grid % grid_mapping) ! CALL SetSwissParameters & ! (grid % grid_mapping, latc = 0.819474, lonc = 0.129845, & ! azimuth = 1.570796, falseE = 600000., falseN = 200000., k = 1.) ! END IF ! !END IF RETURN END SUBROUTINE GridByIniFloatSubSection !============================================================================== !| Description: ! read a `grid_integer` using information stored in ini configuration file ! defined in subsection `[[.. ]]` SUBROUTINE GridByIniIntegerSubSection & ! (ini, grid, section, subsection) USE Inilib, ONLY: & !Imported type definitions: IniList, & !imported routines: IniReadString, IniReadReal, KeyIsPresent, IniReadReal, IniReadInt USE StringManipulation, ONLY: & !Imported routines: StringToUpper, StringToShort USE Chronos, ONLY: & !Imported type definitions: DateTime, & !Imported operands: ASSIGNMENT( = ) USE GeoLib , ONLY: & !Imported routines: DecodeEPSG !SetCRS, ScanDatum, & !SetGeodeticParameters, SetTransverseMercatorParameters, & !SetSwissParameters, & !Imported parameters: !GEODETIC, TM, SOC, & !EAST, WEST, NORTH, SOUTH, ROME40 USE Units, ONLY: & !Imported parameters: degToRad IMPLICIT NONE !arguments with intent in: TYPE (IniList), INTENT(IN) :: ini CHARACTER (LEN = *), INTENT (IN) :: section CHARACTER (LEN = *), INTENT (IN) :: subsection !arguments with intent out: TYPE (grid_integer), INTENT (OUT) :: grid !local variables: CHARACTER (LEN = 100) :: fileFormat CHARACTER (LEN = 300) :: file CHARACTER (LEN = 100) :: variable !!variable to read CHARACTER (LEN = 100) :: stdName !!standard name of the variable to read INTEGER :: epsg !CHARACTER (LEN = 100) :: grid_mapping !CHARACTER (LEN = 100) :: datum TYPE (DateTime) :: gridTime !!time of the grid to read REAL (KIND = float) :: scale_factor REAL (KIND = float) :: offset INTEGER (KIND = long) :: valid_min INTEGER (KIND = long) :: valid_max !REAL (KIND = float) :: centralMeridian !INTEGER :: grid_datum !INTEGER (KIND = short) :: utm_zone INTEGER :: i,j !-----------------------------end of declaration------------------------------- file = IniReadString ('file', ini, section, subsection) IF (KeyIsPresent ('format', ini, section, subsection)) THEN fileFormat = StringToUpper ( IniReadString ('format', ini, section, subsection) ) ELSE CALL Catch ('error', 'GridOperations', & 'format not specified for grid: ', & argument = subsection ) END IF !read grid IF ( fileFormat == 'ESRI-ASCII' ) THEN CALL NewGrid (grid, file, ESRI_ASCII) ELSE IF (fileFormat == 'ESRI-BINARY' ) THEN CALL NewGrid (grid, file, ESRI_BINARY) ELSE IF ( fileFormat == 'NET-CDF' ) THEN IF (KeyIsPresent('variable', ini, section, subsection)) THEN variable = IniReadString ('variable', ini, section, subsection) IF (KeyIsPresent('time', ini, section, subsection)) THEN gridTime = IniReadString ('time', ini, section, subsection) CALL NewGrid (grid, file, NET_CDF, variable = variable, time = gridTime) ELSE CALL NewGrid (grid, file, NET_CDF, variable = variable) END IF ELSE IF (KeyIsPresent('standard_name', ini, section, subsection)) THEN stdName = IniReadString ('standard_name', ini, section, subsection) IF (KeyIsPresent('time', ini, section, subsection)) THEN gridTime = IniReadString ('time', ini, section, subsection) CALL NewGrid (grid, file, NET_CDF, stdName = stdName, time = gridtime) ELSE CALL NewGrid (grid, file, NET_CDF, stdName = stdName) END IF ELSE CALL Catch ('error', 'GridOperations', & 'variable or standard name not defined while reading netcdf: ', & argument = subsection ) END IF ELSE CALL Catch ('error', 'GridOperations', & 'format not supported: ', & argument = fileFormat ) END IF !apply scale factor if given IF (KeyIsPresent ('scale_factor', ini, section, subsection) ) THEN scale_factor = IniReadReal ('scale_factor', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) * scale_factor END IF END DO END DO END IF !add offset if given IF (KeyIsPresent ('offset', ini, section, subsection) ) THEN offset = IniReadReal ('offset', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN grid % mat (i,j) = grid % mat (i,j) + offset END IF END DO END DO END IF !check upper bound if given IF (KeyIsPresent ('valid_max', ini, section, subsection) ) THEN valid_max = IniReadInt ('valid_max', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) > valid_max ) THEN grid % mat (i,j) = valid_max END IF END IF END DO END DO END IF !check lower bound if given IF (KeyIsPresent ('valid_min', ini, section, subsection) ) THEN valid_min = IniReadInt ('valid_min', ini, section, subsection) DO i = 1, grid % idim DO j = 1, grid % jdim IF ( grid % mat (i,j) /= grid % nodata ) THEN IF (grid % mat (i,j) < valid_min ) THEN grid % mat (i,j) = valid_min END IF END IF END DO END DO END IF !read coordinate reference system if given IF (KeyIsPresent ('epsg', ini, section, subsection) ) THEN epsg = IniReadInt ('epsg', ini, section, subsection) grid % grid_mapping = DecodeEPSG (epsg) ELSE CALL Catch ('error', 'GridOperations', & 'epsg not specified for grid: ', & argument = subsection ) END IF !IF (KeyIsPresent ('grid_mapping', ini, section, subsection) ) THEN ! grid_mapping = IniReadString ('grid_mapping', ini, section, subsection) ! IF (KeyIsPresent ('datum', ini, section, subsection) ) THEN ! datum = IniReadString ('datum', ini, section, subsection) ! ELSE ! datum = 'WGS84' ! END IF ! grid_datum = ScanDatum (datum) ! !set reference system ! IF (StringToUpper(grid_mapping) == 'GEODETIC') THEN ! CALL SetCRS (GEODETIC, grid_datum, grid % grid_mapping) ! !default prime_meridian = 0. ! CALL SetGeodeticParameters (grid % grid_mapping, prime_meridian = 0.0) ! ELSE IF (StringToUpper(grid_mapping(1:11)) == 'GAUSS-BOAGA') THEN ! !gauss boaga is a particular case of transverse-mercator ! CALL SetCRS (TM, ROME40, grid % grid_mapping) ! IF (StringToUpper(grid_mapping(13:16)) == 'EAST') THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 15. * degToRad, & ! falseE = 2520000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = 9. * degToRad, & ! falseE = 1500000., falseN = 0., k = 0.9996) ! END IF ! ELSE IF (StringToUpper(grid_mapping(1:3)) == 'UTM') THEN ! !UTM is a particular case of transverse-mercator ! CALL SetCRS (TM, grid_datum, grid % grid_mapping) ! utm_zone = StringToShort(grid_mapping(4:5)) ! IF ( utm_zone >= 31) THEN ! centralMeridian = (6 * utm_zone - 183) * degToRad ! ELSE ! centralMeridian = (6 * utm_zone + 177) * degToRad ! END IF ! IF (StringToUpper(grid_mapping(6:6)) == 'N' ) THEN ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 0., k = 0.9996) ! ELSE ! CALL SetTransverseMercatorParameters & ! (grid % grid_mapping, lat0 = 0., centM = centralMeridian, & ! falseE = 500000., falseN = 10000000., k = 0.9996) ! END IF ! ! ELSE IF (StringToUpper(grid_mapping(1:5)) == 'SWISS') THEN ! CALL SetCRS (SOC, grid_datum, grid % grid_mapping) ! CALL SetSwissParameters & ! (grid % grid_mapping, latc = 0.819474, lonc = 0.129845, & ! azimuth = 1.570796, falseE = 600000., falseN = 200000., k = 1.) ! END IF ! ! !END IF END SUBROUTINE GridByIniIntegerSubSection !============================================================================== !| Description: ! calculates if cell is out of grid space limits LOGICAL FUNCTION IsOutOfGridFloat & ! (i, j, grid) IMPLICIT NONE !Arguments with intent in: INTEGER, INTENT(IN) :: i,j TYPE (grid_real), INTENT(IN) :: grid !----------------------end of declarations------------------------------------- IF (i > grid % idim .OR. j > grid % jdim .OR. i < 1 .OR. j < 1) THEN IsOutOfGridFloat = .TRUE. ELSE IsOutOfGridFloat = .FALSE. ENDIF END FUNCTION IsOutOfGridFloat !============================================================================== !| Description: ! calculates if cell is out of grid space limits LOGICAL FUNCTION IsOutOfGridInteger & ! (i, j, grid) IMPLICIT NONE !Arguments with intent in: INTEGER, INTENT(IN) :: i,j TYPE (grid_integer), INTENT(IN) :: grid !----------------------end of declarations------------------------------------- IF (i > grid % idim .OR. j > grid % jdim .OR. i < 1 .OR. j < 1) THEN IsOutOfGridInteger = .TRUE. ELSE IsOutOfGridInteger = .FALSE. ENDIF END FUNCTION IsOutOfGridInteger !============================================================================== !| Description: ! returns `true` if cell of grid_integer contains no data value LOGICAL FUNCTION CellIsNoDataInteger & ! (i, j, grid) IMPLICIT NONE !Arguments with intent in: INTEGER, INTENT(IN) :: i,j TYPE (grid_integer), INTENT(IN) :: grid !----------------------end of declarations------------------------------------- IF ( grid % mat (i,j) == grid % nodata ) THEN CellIsNoDataInteger = .TRUE. ELSE CellIsNoDataInteger = .FALSE. END IF RETURN END FUNCTION CellIsNoDataInteger !============================================================================== !| Description: ! return `true` if cell of `grid_real` contains no data value LOGICAL FUNCTION CellIsNoDataFloat & ! (i, j, grid) IMPLICIT NONE !Arguments with intent in: INTEGER, INTENT(IN) :: i,j TYPE (grid_real), INTENT(IN) :: grid !----------------------end of declarations------------------------------------- IF ( grid % mat (i,j) == grid % nodata ) THEN CellIsNoDataFloat = .TRUE. ELSE CellIsNoDataFloat = .FALSE. END IF RETURN END FUNCTION CellIsNoDataFloat !============================================================================== !| Description: ! return `false` if cell is out of grid either contains nodata value, ! `true` otherwise. LOGICAL FUNCTION CellIsValidInteger & ! (i, j, grid) IMPLICIT NONE !Arguments with intent in: INTEGER, INTENT(IN) :: i,j TYPE (grid_integer), INTENT(IN) :: grid !----------------------end of declarations------------------------------------- CellIsValidInteger = .TRUE. IF ( IsOutOfGrid (i, j, grid) ) THEN CellIsValidInteger = .FALSE. RETURN ELSE IF ( grid % mat (i,j) == grid % nodata ) THEN CellIsValidInteger = .FALSE. ELSE CellIsValidInteger = .TRUE. END IF END IF RETURN END FUNCTION CellIsValidInteger !============================================================================== !| Description: ! return `false` if cell is out of grid either contains nodata value, ! `true` otherwise. LOGICAL FUNCTION CellIsValidFloat & ! (i, j, grid) IMPLICIT NONE !Arguments with intent in: INTEGER, INTENT(IN) :: i,j TYPE (grid_real), INTENT(IN) :: grid !----------------------end of declarations------------------------------------- CellIsValidFloat = .TRUE. IF ( IsOutOfGrid (i, j, grid) ) THEN CellIsValidFloat = .FALSE. RETURN ELSE IF ( grid % mat (i,j) == grid % nodata ) THEN CellIsValidFloat = .FALSE. ELSE CellIsValidFloat = .TRUE. END IF END IF RETURN END FUNCTION CellIsValidFloat !============================================================================== !! Description: !| Extracts only the cells on the external border. Other cells are ! assigned `nodata`. Border cell is the one that has at least a ! `nodata` value in the neighbouring 8 cells. SUBROUTINE ExtractBorderFloat & ! (grid, border, cardinal) IMPLICIT NONE !Arguments with intent in: TYPE (grid_real), INTENT(IN) :: grid LOGICAL, INTENT(IN), OPTIONAL :: cardinal !Arguments with intent in: TYPE (grid_real) :: border !Local declaration: INTEGER :: i,j LOGICAL :: foundNodata INTEGER :: row, col LOGICAL :: fourCells !!true if to consider only four cells in cardinal directions !---------------------------end of declarations-------------------------------- !Allocate space for grid containing values on the border CALL NewGrid (border, grid) IF (PRESENT(cardinal)) THEN IF (cardinal) THEN fourCells = .TRUE. ELSE fourCells = .FALSE. END IF ELSE fourCells = .FALSE. END IF !scan grid DO i = 1, border % idim DO j = 1, border % jdim IF (grid % mat (i,j) /= grid % nodata) THEN foundNodata = .FALSE. !check EAST cell row = i col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check SOUTH-EAST cell IF ( .NOT. fourCells) THEN row = i + 1 col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF !check SOUTH cell row = i + 1 col = j IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check SOUTH-WEST cell IF (.NOT. fourCells) THEN row = i + 1 col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF !check WEST cell row = i col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check NORTH-EAST cell IF (.NOT. fourCells) THEN row = i - 1 col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF !check NORTH cell row = i - 1 col = j IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check NORTH-EAST cell IF (.NOT. fourCells) THEN row = i - 1 col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF IF ( .NOT. foundNodata ) THEN border % mat (i,j) = border % nodata END IF END IF END DO END DO END SUBROUTINE ExtractBorderFloat !============================================================================== !| Description: ! Extracts only the cells on the external border. Other cells are ! assigned `nodata`. Border cell is the one that has at least a ! `nodata` value in the neighbouring 8 cells. If `cardinal` is passed ! the routine checks only the four cells in the cardinal direction. ! This option is used to obtain border without duplicates. Default is ! check all the cells. SUBROUTINE ExtractBorderInteger & ! (grid, border, cardinal) IMPLICIT NONE !Arguments with intent in: TYPE (grid_integer), INTENT(IN) :: grid LOGICAL, INTENT(IN), OPTIONAL :: cardinal !Arguments with intent out: TYPE (grid_integer), INTENT(OUT) :: border !Local declaration: INTEGER :: i,j LOGICAL :: foundNodata INTEGER :: row, col LOGICAL :: fourCells !!true if to consider only four cells in cardinal directions !---------------------------end of declarations-------------------------------- !Allocate space for grid containing values on the border CALL NewGrid (border, grid) IF (PRESENT(cardinal)) THEN IF (cardinal) THEN fourCells = .TRUE. ELSE fourCells = .FALSE. END IF ELSE fourCells = .FALSE. END IF !scan grid DO i = 1, border % idim DO j = 1, border % jdim IF (grid % mat (i,j) /= grid % nodata) THEN foundNodata = .FALSE. !check EAST cell row = i col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check SOUTH-EAST cell IF ( .NOT. fourCells) THEN row = i + 1 col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF !check SOUTH cell row = i + 1 col = j IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check SOUTH-WEST cell IF (.NOT. fourCells) THEN row = i + 1 col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF !check WEST cell row = i col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check NORTH-EAST cell IF (.NOT. fourCells) THEN row = i - 1 col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF !check NORTH cell row = i - 1 col = j IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF !check NORTH-EAST cell IF (.NOT. fourCells) THEN row = i - 1 col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,border) ) THEN IF (grid % mat (row,col) == grid % nodata) THEN foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF ELSE foundNodata = .TRUE. border % mat (i,j) = grid % mat (i,j) CYCLE END IF END IF IF ( .NOT. foundNodata ) THEN border % mat (i,j) = border % nodata END IF END IF END DO END DO RETURN END SUBROUTINE ExtractBorderInteger !============================================================================== !| Description: ! Create a new `grid_real` with cellsize different from input grid ! The content of the created grid is filled in with nearest neighbor method SUBROUTINE ResampleFloatCell & ! (grid, resampledGrid, newCellsize) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_real), INTENT(IN) :: grid REAL (KIND = float), INTENT(IN) :: newCellsize !Arguments with intent(out): TYPE (grid_real), INTENT(OUT) :: resampledGrid !Local declarations: REAL :: x, y INTEGER :: i, j, iold, jold !---------------------------end of declarations-------------------------------- !compute number of rows and columns of the resampled grid resampledGrid % idim = INT(grid%cellsize * grid%idim / newCellsize) + 1 resampledGrid % jdim = INT(grid%cellsize * grid%jdim / newCellsize) + 1 !assign spatial information resampledGrid % cellsize = newCellsize resampledGrid % xllcorner = grid % xllcorner resampledGrid % yllcorner = grid % yllcorner !allocate resampled grid ALLOCATE ( resampledGrid % mat (resampledGrid%idim, resampledGrid%jdim)) !copy information from grid to resampled grid resampledGrid % standard_name = grid % standard_name resampledGrid % long_name = grid % long_name resampledGrid % units = grid % units resampledGrid % varying_mode = grid % varying_mode resampledGrid % nodata = grid % nodata resampledGrid % valid_min = grid % valid_min resampledGrid % valid_max = grid % valid_max resampledGrid % reference_time = grid % reference_time resampledGrid % current_time = grid % current_time resampledGrid % time_index = grid % time_index resampledGrid % time_unit = grid % time_unit resampledGrid % esri_pe_string = grid % esri_pe_string resampledGrid % grid_mapping = grid % grid_mapping !fill in resampled grid DO i = 1, resampledGrid % idim DO j = 1, resampledGrid % jdim CALL GetXY (i, j, resampledGrid, x, y) CALL GetIJ (x, y, grid, iold, jold) IF (iold > 0 .AND. jold > 0 .AND. iold <= grid % idim .AND. jold <= grid % jdim) THEN resampledGrid % mat (i,j) = grid % mat (iold, jold) ELSE resampledGrid % mat (i,j) = resampledGrid % nodata END IF END DO END DO END SUBROUTINE ResampleFloatCell !============================================================================== !| Description: ! Create a new `grid_integer` with cellsize different from input grid ! The content of the created grid is filled in with nearest neighbor method SUBROUTINE ResampleIntegerCell & ! (grid, resampledGrid, newCellsize) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_integer), INTENT(IN) :: grid REAL (KIND = float), INTENT(IN) :: newCellsize !Arguments with intent(out): TYPE (grid_integer), INTENT(OUT) :: resampledGrid !Local declarations: REAL :: x, y INTEGER :: i, j, iold, jold !---------------------------end of declarations-------------------------------- !compute number of rows and columns of the resampled grid resampledGrid % idim = INT(grid%cellsize * grid%idim / newCellsize) + 1 resampledGrid % jdim = INT(grid%cellsize * grid%jdim / newCellsize) + 1 !assign spatial information resampledGrid % cellsize = newCellsize resampledGrid % xllcorner = grid % xllcorner resampledGrid % yllcorner = grid % yllcorner !allocate resampled grid ALLOCATE ( resampledGrid % mat (resampledGrid%idim, resampledGrid%jdim)) !copy information from grid to resampled grid resampledGrid % standard_name = grid % standard_name resampledGrid % long_name = grid % long_name resampledGrid % units = grid % units resampledGrid % varying_mode = grid % varying_mode resampledGrid % nodata = grid % nodata resampledGrid % valid_min = grid % valid_min resampledGrid % valid_max = grid % valid_max resampledGrid % reference_time = grid % reference_time resampledGrid % current_time = grid % current_time resampledGrid % time_index = grid % time_index resampledGrid % time_unit = grid % time_unit resampledGrid % esri_pe_string = grid % esri_pe_string resampledGrid % grid_mapping = grid % grid_mapping !fill in resampled grid DO i = 1, resampledGrid % idim DO j = 1, resampledGrid % jdim CALL GetXY (i, j, resampledGrid, x, y) CALL GetIJ (x, y, grid, iold, jold) IF (iold > 0 .AND. jold > 0 .AND. iold <= grid % idim .AND. jold <= grid % jdim) THEN resampledGrid % mat (i,j) = grid % mat (iold, jold) ELSE resampledGrid % mat (i,j) = resampledGrid % nodata END IF END DO END DO END SUBROUTINE ResampleIntegerCell !============================================================================== !| Description: ! Fill in a grid with a different cellsize from input grid. ! Both input grid and output grid exist. SUBROUTINE ResampleFloat & ! (grid, resampledGrid) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_real), INTENT(IN) :: grid !Arguments with intent(inout): TYPE (grid_real), INTENT(INOUT) :: resampledGrid !Local declarations: REAL :: x, y INTEGER :: i, j, iold, jold LOGICAL :: check !---------------------------end of declarations-------------------------------- !check that input and output grid have the same coordinate reference system IF ( .NOT. grid % grid_mapping == resampledGrid % grid_mapping) THEN CALL Catch ('error', 'GridOperations', & 'coordinate reference system of resampled grid differs from input grid' ) END IF !fill in resampled grid. Skip nodata DO i = 1, resampledGrid % idim DO j = 1, resampledGrid % jdim IF (resampledGrid % mat (i,j) /= resampledGrid % nodata) THEN CALL GetXY (i, j, resampledGrid, x, y) CALL GetIJ (x, y, grid, iold, jold, check) IF (check) THEN resampledGrid % mat (i,j) = grid % mat (iold, jold) ELSE resampledGrid % mat (i,j) = resampledGrid % nodata END IF END IF END DO END DO END SUBROUTINE ResampleFloat !============================================================================== !| Description: ! Fill in a grid with a different cellsize from input grid. ! Both input grid and output grid exist. SUBROUTINE ResampleInteger & ! (grid, resampledGrid) IMPLICIT NONE ! Arguments with intent(in): TYPE (grid_integer), INTENT(IN) :: grid !Arguments with intent(inout): TYPE (grid_integer), INTENT(INOUT) :: resampledGrid !Local declarations: REAL :: x, y INTEGER :: i, j, iold, jold LOGICAL :: check !---------------------------end of declarations-------------------------------- !check that input and output grid have the same coordinate reference system IF ( .NOT. grid % grid_mapping == resampledGrid % grid_mapping) THEN CALL Catch ('error', 'GridOperations', & 'coordinate reference system of resampled grid differs from input grid' ) END IF !fill in resampled grid. The content of resampledGird is totally overwritten DO i = 1, resampledGrid % idim DO j = 1, resampledGrid % jdim IF (resampledGrid % mat (i,j) /= resampledGrid % nodata) THEN CALL GetXY (i, j, resampledGrid, x, y) CALL GetIJ (x, y, grid, iold, jold, check) IF (check) THEN resampledGrid % mat (i,j) = grid % mat (iold, jold) ELSE resampledGrid % mat (i,j) = resampledGrid % nodata END IF END IF END DO END DO END SUBROUTINE ResampleInteger !============================================================================== !| Description: ! assign value of mask real to mat real SUBROUTINE AssignGridReal & ! (mat, mask) IMPLICIT NONE !Arguments with intent(in): TYPE(grid_real),INTENT(IN) :: mask !Arguments with intent (inout) TYPE(grid_real),INTENT(INOUT):: mat !Local declarations: INTEGER :: i,j !---------------------------end of declarations-------------------------------- !check spatial reference !IF ( .NOT. CRSisEqual (mask, mat, .TRUE.) ) THEN IF ( .NOT. CRSisEqual (mask, mat) ) THEN CALL Catch ('error', 'GridOperations', & 'while assigning grid content from another grid: ', & argument = 'spatial reference not equal' ) END IF DO i = 1, mat % idim DO j = 1, mat % jdim IF (mat % mat (i,j) /= mat % nodata) THEN mat % mat(i,j) = mask % mat(i,j) END IF END DO END DO END SUBROUTINE AssignGridReal !============================================================================== !| Description: ! assign value of mask integer to mat integer SUBROUTINE AssignGridInteger & ! (mat, mask) IMPLICIT NONE !Arguments with intent(in): TYPE(grid_integer),INTENT(IN) :: mask !Arguments with intent (inout) TYPE(grid_integer),INTENT(INOUT):: mat !Local declarations: INTEGER :: i,j !---------------------------end of declarations-------------------------------- !check spatial reference !IF ( .NOT. CRSisEqual (mask, mat, .TRUE.) ) THEN IF ( .NOT. CRSisEqual (mask, mat) ) THEN CALL Catch ('error', 'GridOperations', & 'while assigning grid content from another grid: ', & argument = 'spatial reference not equal' ) END IF DO i = 1, mat % idim DO j = 1, mat % jdim IF (mat % mat (i,j) /= mat % nodata) THEN mat % mat(i,j) = mask % mat(i,j) END IF END DO END DO END SUBROUTINE AssignGridInteger !============================================================================== !| Description: ! assign value of mask real to mat integer. real numbers are truncated to ! integer part. SUBROUTINE AssignGridRealInteger & ! (mat, mask) IMPLICIT NONE !Arguments with intent(in): TYPE(grid_real),INTENT(IN) :: mask !Arguments with intent (inout) TYPE(grid_integer),INTENT(INOUT):: mat !Local declarations: INTEGER :: i,j !---------------------------end of declarations-------------------------------- !check spatial reference !IF ( .NOT. CRSisEqual (mask, mat, .TRUE.) ) THEN IF ( .NOT. CRSisEqual (mask, mat) ) THEN CALL Catch ('error', 'GridOperations', & 'while assigning grid content from another grid: ', & argument = 'spatial reference not equal' ) END IF DO i = 1, mat % idim DO j = 1, mat % jdim IF (mat % mat (i,j) /= mat % nodata) THEN !truncate to integer part mat % mat(i,j) = INT ( mask % mat(i,j) ) ELSE !fix nodata mat % mat(i,j) = -9999 END IF END DO END DO mat % nodata = -9999 END SUBROUTINE AssignGridRealInteger !============================================================================== !| Description: ! assign value of mask integer to mat real SUBROUTINE AssignGridIntegerReal & ! (mat, mask) IMPLICIT NONE !Arguments with intent(in): TYPE(grid_integer),INTENT(IN) :: mask !Arguments with intent (inout) TYPE(grid_real),INTENT(INOUT):: mat !Local declarations: INTEGER :: i,j !---------------------------end of declarations-------------------------------- !check spatial reference !IF ( .NOT. CRSisEqual (mask, mat, .TRUE.) ) THEN IF ( .NOT. CRSisEqual (mask, mat) ) THEN CALL Catch ('error', 'GridOperations', & 'while assigning grid content from another grid: ', & argument = 'spatial reference not equal' ) END IF DO i = 1, mat % idim DO j = 1, mat % jdim IF (mat % mat (i,j) /= mat % nodata) THEN !cast to real number mat % mat(i,j) = REAL ( mask % mat(i,j) ) ELSE !fix nodata mat % mat(i,j) = -9999.9 END IF END DO END DO mat % nodata = -9999.9 END SUBROUTINE AssignGridIntegerReal !============================================================================== !| Description: ! assign value to mat SUBROUTINE AssignReal & ! (mat, num) IMPLICIT NONE !Arguments with intent(in): REAL (KIND = float),INTENT(IN) :: num !Arguments with intent (inout) TYPE(grid_real),INTENT(INOUT):: mat !Local declarations: INTEGER :: i,j !---------------------------end of declarations-------------------------------- DO i = 1, mat % idim DO j = 1, mat % jdim IF (mat % mat (i,j) /= mat % nodata) THEN mat % mat(i,j) = num END IF END DO END DO END SUBROUTINE AssignReal !============================================================================== !| Description: ! assign value to mat SUBROUTINE AssignInteger & ! (mat, num) IMPLICIT NONE !Arguments with intent(in): INTEGER,INTENT(IN) :: num !Arguments with intent (inout) TYPE(grid_integer),INTENT(INOUT):: mat !Local declarations: INTEGER :: i,j !---------------------------end of declarations-------------------------------- DO i = 1, mat % idim DO j = 1, mat % jdim IF (mat % mat (i,j) /= mat % nodata) THEN mat % mat(i,j) = num END IF END DO END DO END SUBROUTINE AssignInteger !------------------------------------------------------------------------------ !| Description !! compute area ([m2) of grid excluding nodata FUNCTION GetAreaOfGridInteger & ! (grid) & ! RESULT(area) IMPLICIT NONE !arguments with intent(in): TYPE(grid_integer), INTENT (IN) :: grid !Local declarations: REAL (KIND = float) :: area INTEGER (KIND = short) :: i, j !------------------------------------end of declarations----------------------- area = 0. DO i = 1, grid % idim DO j = 1, grid % jdim IF (grid % mat (i,j) /= grid % nodata) THEN area = area + CellArea (grid, i, j) END IF END DO END DO END FUNCTION GetAreaOfGridInteger !------------------------------------------------------------------------------ !| Description ! compute area (m2) of grid excluding nodata FUNCTION GetAreaOfGridFloat & ! (grid) & ! RESULT(area) IMPLICIT NONE !arguments with intent(in): TYPE(grid_real), INTENT (IN) :: grid !Local declarations: REAL (KIND = float) :: area INTEGER (KIND = short) :: i, j !------------------------------------end of declarations----------------------- area = 0. DO i = 1, grid % idim DO j = 1, grid % jdim IF (grid % mat (i,j) /= grid % nodata) THEN area = area + CellArea (grid, i, j) END IF END DO END DO END FUNCTION GetAreaOfGridFloat !============================================================================== !| Description: ! Apply a shift to `grid_real`. Modifies `xllcorner` and `yllcorner` SUBROUTINE ShiftReal & ! (gridin, gridout, shifteast, shiftnorth) IMPLICIT NONE !Arguments with intent in TYPE (grid_real), INTENT(IN) :: gridin REAL (KIND = float), INTENT(IN) :: shifteast !!amount of shift in east direction REAL (KIND = float), INTENT(IN) :: shiftnorth !!amount of shift in north direction !Arguments with intent(out): TYPE (grid_real), INTENT(OUT) :: gridout !---------------------end of declarations-------------------------------------- CALL NewGrid (gridout, gridin) gridout = gridin gridout % xllcorner = gridin % xllcorner + shifteast gridout % yllcorner = gridin % yllcorner + shiftnorth RETURN END SUBROUTINE ShiftReal !============================================================================== !| Description: ! Apply a shift to` grid_integer`. Creates a new grid with `xllcorner` ! and `yllcorner` modified SUBROUTINE ShiftInteger & ! (gridin, gridout, shifteast, shiftnorth) IMPLICIT NONE !Arguments with intent in TYPE (grid_integer), INTENT(IN) :: gridin REAL (KIND = float), INTENT(IN) :: shifteast !!amount of shift in east direction REAL (KIND = float), INTENT(IN) :: shiftnorth !!amount of shift in north direction !Arguments with intent(out): TYPE (grid_integer), INTENT(OUT) :: gridout !---------------------end of declarations-------------------------------------- CALL NewGrid (gridout, gridin) gridout = gridin gridout % xllcorner = gridin % xllcorner + shifteast gridout % yllcorner = gridin % yllcorner + shiftnorth RETURN END SUBROUTINE ShiftInteger !============================================================================== !| Description: ! return an array 1D of numbers different than `nodata` in a `grid_integer` SUBROUTINE Grid2vectorInteger & ! (grid, vector) IMPLICIT NONE !Arguments with intent in TYPE (grid_integer), INTENT(IN) :: grid !Arguments with intent out INTEGER (KIND = short), INTENT (OUT), ALLOCATABLE :: vector (:) !local declarations: INTEGER (KIND = short) :: i, j, count, istat !---------------------end of declarations-------------------------------------- !count number of actual values in grid, skip nodata count = 0 DO i = 1, grid % idim DO j = 1, grid % jdim IF (grid % mat (i,j) /= grid % nodata) THEN count = count + 1 END IF END DO END DO !allocate vector ALLOCATE (vector (count), STAT = istat) !fill in vector count = 0 DO i = 1, grid % idim DO j = 1, grid % jdim IF (grid % mat (i,j) /= grid % nodata) THEN count = count + 1 vector (count) = grid % mat (i,j) END IF END DO END DO RETURN END SUBROUTINE Grid2vectorInteger !============================================================================== !| Description: ! return an array 1D of numbers different than `nodata` in a `grid_real` SUBROUTINE Grid2vectorFloat & ! (grid, vector) IMPLICIT NONE !Arguments with intent in TYPE (grid_real), INTENT(IN) :: grid !Arguments with intent out REAL (KIND = float), INTENT (OUT), ALLOCATABLE :: vector (:) !local declarations: INTEGER (KIND = short) :: i, j, count, istat !---------------------end of declarations-------------------------------------- !count number of actual values in grid, skip nodata count = 0 DO i = 1, grid % idim DO j = 1, grid % jdim IF (grid % mat (i,j) /= grid % nodata) THEN count = count + 1 END IF END DO END DO !allocate vector ALLOCATE (vector (count), STAT = istat) !fill in vector count = 0 DO i = 1, grid % idim DO j = 1, grid % jdim IF (grid % mat (i,j) /= grid % nodata) THEN count = count + 1 vector (count) = grid % mat (i,j) END IF END DO END DO RETURN END SUBROUTINE Grid2vectorFloat END MODULE GridOperations